import FirstTitle from "@/components/FirstTitle";
import { Description } from "@/components/description";
import SubTitle from "@/components/subTitle";
import EffectContainer from "@/components/effectContainer";
import { requireImg } from "@/utils/common.ts";
import Code from "@/components/code";

import "./index.module.scss";

export const ReduxLearn = () => {
  return (
    <>
      <FirstTitle title="Redux 学习" />
      <SubTitle title="react-redux 方式" />
      <Description
        info={
          <>
            <span>
              react-redux 是一个用于将 Redux 状态管理库与 React
              应用程序集成的官方绑定库。它提供了两种主要的功能：Provider 组件和
              connect 高阶组件（HOC），以及从 v7 开始引入的 useSelector 和
              useDispatch Hooks。
              <img
                style={{ width: "100%", height: "300px", padding: "20px" }}
                src={requireImg("react-redux模型图.png")}
                alt=""
              />
            </span>
            <span>下面是如何在 React 应用中使用 react-redux 的基本步骤：</span>
            <span>
              1. 安装 react-redux 和 redux 如果你还没有安装 react-redux 和
              redux，可以通过 npm 或 yarn 进行安装：
            </span>
            <span style={{ width: "100%", paddingLeft: "10px" }}>
              <Code type="npm" content={"npm install react-redux red"}></Code>
            </span>
            <span>
              2. 创建 Store 首先，你需要创建一个 Redux store。这通常涉及到定义
              actions、reducers 和 store 本身。
            </span>
            <span style={{ width: "100%", paddingLeft: "10px" }}>
              Actions Actions 是简单的 JavaScript
              对象，它们描述了应用中发生的事件。它们通常由 action creators
              函数返回，这些函数返回一个 action 对象。
              <Code
                content={
                  "// actions.js\n" +
                  "export const addTodo = (text) => {\n" +
                  "  return {" +
                  " type: 'ADD_TODO'," +
                  "text" +
                  " };\n" +
                  "};"
                }
              ></Code>
            </span>
            <span style={{ width: "100%", paddingLeft: "10px" }}>
              Reducers Reducers 是纯函数，它们接收当前 state 和一个
              action，然后返回新的 state
              <Code
                content={
                  "// reducers.js\n" +
                  "const initialState = [];\n" +
                  "export default function todoReducer(state = initialState, action) {\n" +
                  "  switch (action.type) {\n" +
                  "    case 'ADD_TODO':\n" +
                  "      return [...state, { text: action.text, completed: false }];\n" +
                  "    // 其他 cases...\n" +
                  "    default:\n" +
                  "      return state;\n" +
                  "  }\n" +
                  "}"
                }
              ></Code>
            </span>
            <span style={{ width: "100%", paddingLeft: "10px" }}>
              Store Store 是 Redux 的中心数据存储。你可以通过 createStore
              函数结合 reducer 来创建
              store。若有多个不同的reducer可以使用combineReducers函数合并成一个大的reducer
              <Code
                content={
                  "// store.js\n" +
                  "import { createStore } from 'redux';\n" +
                  "import todoReducer from './reducers';\n" +
                  "\n" +
                  "const store = createStore(todoReducer);"
                }
              ></Code>
            </span>
            <span>
              3. 使用 Provider 在你的根组件中，你需要使用 Provider 组件将 store
              提供给整个应用。
            </span>
            <span style={{ width: "100%", paddingLeft: "10px" }}>
              <Code
                content={
                  "// index.js\n" +
                  "import React from 'react';\n" +
                  "import ReactDOM from 'react-dom';\n" +
                  "import { Provider } from 'react-redux';\n" +
                  "import store from './store';\n" +
                  "import App from './App';\n" +
                  "\n" +
                  "ReactDOM.render(\n" +
                  "  <Provider store={store}>\n" +
                  "    <App />\n" +
                  "  </Provider>,\n" +
                  "  document.getElementById('root')\n" +
                  ");"
                }
              ></Code>
            </span>
            <span>
              4. 使用 connect 或 Hooks 在你的组件中，你可以使用 connect 函数或
              useSelector 和 useDispatch Hooks 来访问和修改 Redux store
              中的状态。
            </span>
            <span style={{ width: "100%", paddingLeft: "10px" }}>
              使用 connect 对于类组件，你可以使用 connect 函数。
              <Code
                content={
                  "// MyComponent.js\n" +
                  "import React from 'react';\n" +
                  "import { connect } from 'react-redux';\n" +
                  "import { addTodo } from './actions';\n" +
                  "\n" +
                  "const MyComponent = ({ todos, addTodo }) => (\n" +
                  "  <div>\n" +
                  "    {/* 渲染 todos */}\n" +
                  "    <button onClick={() => addTodo('New Todo')}>Add Todo</button>\n" +
                  "  </div>\n" +
                  ");\n" +
                  "\n" +
                  "const mapStateToProps = (state) => ({\n" +
                  "  todos: state,\n" +
                  "});\n" +
                  "\n" +
                  "const mapDispatchToProps = {\n" +
                  "  addTodo,\n" +
                  "};\n" +
                  "\n" +
                  "export default connect(mapStateToProps, mapDispatchToProps)(MyComponent);"
                }
              ></Code>
            </span>
            <span style={{ width: "100%", paddingLeft: "10px" }}>
              使用 Hooks 对于函数组件，你可以使用 useSelector 和 useDispatch
              Hooks。
              <Code
                content={
                  "// MyComponent.js\n" +
                  "import React from 'react';\n" +
                  "import { useSelector, useDispatch } from 'react-redux';\n" +
                  "import { addTodo } from './actions';\n" +
                  "\n" +
                  "const MyComponent = () => {\n" +
                  "  const todos = useSelector((state) => state);\n" +
                  "  const dispatch = useDispatch();\n" +
                  "\n" +
                  "  return (\n" +
                  "    <div>\n" +
                  "      {/* 渲染 todos */}\n" +
                  "      <button onClick={() => dispatch(addTodo('New Todo'))}>Add Todo</button>\n" +
                  "    </div>\n" +
                  "  );\n" +
                  "};\n" +
                  "\n" +
                  "export default MyComponent;"
                }
              ></Code>
            </span>
          </>
        }
      ></Description>

      <SubTitle title="@reduxjs/toolkit 方式" />
      <Description
        info={
          <>
            <span>
              @reduxjs/toolkit 是 Redux 官方提供的一个工具包，旨在简化 Redux
              的使用，减少样板代码，提高开发效率。它内置了 Redux Thunk、Redux
              DevTools 和其他一些实用功能，使得创建 actions、reducers 和 store
              变得更加简单。
            </span>
            <span>
              下面是使用 @reduxjs/toolkit 的基本步骤：下面是使用
              @reduxjs/toolkit 的基本步骤：
            </span>
            <span>
              1. 安装依赖 确保你已经安装了 @reduxjs/toolkit 和 react-redux：
            </span>
            <span style={{ width: "100%", paddingLeft: "10px" }}>
              <Code
                type="npm"
                content={"npm install @reduxjs/toolkit react-redux"}
              ></Code>
            </span>
            <span>
              2. 创建 Slice Slice 是 @reduxjs/toolkit 中用于定义 actions 和
              reducers 的模块。每个 slice 都有自己的 state 形状和一组相关的
              action creators 和 reducer。
            </span>
            <span style={{ width: "100%", paddingLeft: "10px" }}>
              <Code
                content={
                  "// slices/todoSlice.js\n" +
                  "import { createSlice } from '@reduxjs/toolkit';\n" +
                  "\n" +
                  "const initialState = [];\n" +
                  "\n" +
                  "export const todoSlice = createSlice({\n" +
                  "  name: 'todos',\n" +
                  "  initialState,\n" +
                  "  reducers: {\n" +
                  "    addTodo: (state, action) => {\n" +
                  "      state.push({ id: action.payload.id, text: action.payload.text, completed: false });\n" +
                  "    },\n" +
                  "    toggleTodo: (state, action) => {\n" +
                  "      const todo = state.find((todo) => todo.id === action.payload.id);\n" +
                  "      if (todo) todo.completed = !todo.completed;\n" +
                  "    },\n" +
                  "  },\n" +
                  "});\n" +
                  "\n" +
                  "export const { addTodo, toggleTodo } = todoSlice.actions;\n" +
                  "\n" +
                  "export default todoSlice.reducer;"
                }
              ></Code>
            </span>
            <span>
              3. 创建 Store 使用 configureStore 方法来创建
              store，这个方法会自动设置中间件如 thunk 和 devtools
            </span>
            <span style={{ width: "100%", paddingLeft: "10px" }}>
              <Code
                content={
                  "// store.js\n" +
                  "import { configureStore } from '@reduxjs/toolkit';\n" +
                  "import todoReducer from '../slices/todoSlice';\n" +
                  "\n" +
                  "export const store = configureStore({\n" +
                  "  reducer: {\n" +
                  "    todos: todoReducer,\n" +
                  "  },\n" +
                  "});\n" +
                  "\n" +
                  "// Infer the `RootState` and `AppDispatch` types from the store itself\n" +
                  "export type RootState = ReturnType<typeof store.getState>;\n" +
                  "// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}\n" +
                  "export type AppDispatch = typeof store.dispatch;"
                }
              ></Code>
            </span>
            <span>4. 使用 Provider 在根组件中使用 Provider 来提供 store。</span>
            <span style={{ width: "100%", paddingLeft: "10px" }}>
              <Code
                content={
                  "// index.js\n" +
                  "import React from 'react';\n" +
                  "import ReactDOM from 'react-dom';\n" +
                  "import { Provider } from 'react-redux';\n" +
                  "import store from './store';\n" +
                  "import App from './App';\n" +
                  "\n" +
                  "ReactDOM.render(\n" +
                  "  <Provider store={store}>\n" +
                  "    <App />\n" +
                  "  </Provider>,\n" +
                  "  document.getElementById('root')\n" +
                  ");"
                }
              ></Code>
            </span>
            <span>
              5. 使用 useSelector 和 useDispatch 在你的组件中使用 useSelector 和
              useDispatch Hooks 来访问和操作状态。
            </span>
            <span style={{ width: "100%", paddingLeft: "10px" }}>
              <Code
                content={
                  "// MyComponent.js\n" +
                  "import React from 'react';\n" +
                  "import { useSelector, useDispatch } from 'react-redux';\n" +
                  "import { addTodo, toggleTodo } from '../slices/todoSlice';\n" +
                  "\n" +
                  "const MyComponent = () => {\n" +
                  "  const todos = useSelector((state: RootState) => state.todos);\n" +
                  "  const dispatch = useDispatch<AppDispatch>();\n" +
                  "\n" +
                  "  const handleAddTodo = () => {\n" +
                  "    dispatch(addTodo({ id: Date.now(), text: 'Learn Redux Toolkit' }));\n" +
                  "  };\n" +
                  "\n" +
                  "  const handleToggleTodo = (id: number) => {\n" +
                  "    dispatch(toggleTodo({ id }));\n" +
                  "  };\n" +
                  "\n" +
                  "  return (\n" +
                  "    <div>\n" +
                  "      <ul>\n" +
                  "        {todos.map((todo) => (\n" +
                  "          <li key={todo.id} onClick={() => handleToggleTodo(todo.id)}>\n" +
                  "            {todo.text} - {todo.completed ? 'Completed' : 'Pending'}\n" +
                  "          </li>\n" +
                  "        ))}\n" +
                  "      </ul>\n" +
                  "      <button onClick={handleAddTodo}>Add Todo</button>\n" +
                  "    </div>\n" +
                  "  );\n" +
                  "};\n" +
                  "\n" +
                  "export default MyComponent;"
                }
              ></Code>
            </span>
          </>
        }
      ></Description>
    </>
  );
};
